import { Dispatch } from '../../react/src/currentDispatcher';
import { Action } from 'shared/ReactTypes';
import { isSubsetOfLanes, Lane, mergeLanes, NoLane } from './fiberLanes';
import { FiberNode } from './fiber';

// 代表更新的数据结构
export interface Update<State> {
	action: Action<State>; // 一个具体的state 或者一个函数
	lane: Lane; // 当前更新的 优先级别
	next: Update<any> | null; // 执行下一个 Update
	hasEagerState: boolean;
	eagerState: State | null;
}

// 消费更新的数据结构
export interface UpdateQueue<State> {
	shared: {
		pending: Update<State> | null; // // pending 表示 最后插入的 update
	};
	dispatch: Dispatch<State> | null;
}

// 创建一个 更新
export const createUpdate = <State>(
	action: Action<State>,
	lane: Lane,
	hasEagerState = false,
	eagerState = null
): Update<State> => {
	return {
		action,
		lane,
		next: null,
		hasEagerState,
		eagerState
	};
};

// 创建一个消费更新
export const createUpdateQueue = <State>() => {
	return {
		shared: {
			pending: null
		},
		// 为了 兼容 hooks queue 中增加 dispatch 属性
		dispatch: null
	} as UpdateQueue<State>;
};

// 将Update 设计成链表的 目录是 可能 一个 事件处理函数里面 同时执行多个 dispatch 或setState
// 那么将他们 传的state 存入链表中 pending 始终指向 最后插入的 update   pending.next 始终指向 第一个插入的 update
// 将更新添加到消费更新中
export const enqueueUpdate = <State>(
	updateQueue: UpdateQueue<State>,
	update: Update<State>,
	fiber: FiberNode,
	lane: Lane
) => {
	const pending = updateQueue.shared.pending;
	// pending 表示 最后插入的 update
	if (pending === null) {
		// 先插入a
		// pending 指向 a next->指向 a
		// 说明之前没有 设置更新
		// 那就将 update.next 设置为自己 形成环形链表 自己指向自己
		update.next = update;
	} else {
		// 之前有update 了
		// pending = b -> a -> b
		// pending = c -> a -> b -> c

		// 第二次插入 b
		// b.next = a.next;

		// 比如 现在 是 1 2 3 4
		// 目前pending 指向 4 4.next 指向1
		// 将 5插入
		//  那就需要 将 5.next  = 4.next
		// 让 5 的next 指向1
		update.next = pending.next;
		// 然后将 4 和 5链起来
		// 就是pending.next = 5
		// a.next = b
		pending.next = update;
		// 最后 变成 1 2 3 4 5 5.next 指向1;
	}

	// 将update 设置给pending

	//  pending = b;
	updateQueue.shared.pending = update;
	// 结果就是一个 循环链表 pending ->b b.next ->a a.next->b
	// 如果再加一个c 那就是 pending ->c c.next ->a a.next->b b.next -c

	// 这样做的好处 就是updateQueue.shared.pending 肯定指向 最后一个update
	// pdateQueue.shared.pending.next 肯定指向 第一个插入的update

	fiber.lanes = mergeLanes(fiber.lanes, lane);
	const alternate = fiber.alternate;
	if (alternate !== null) {
		alternate.lanes = mergeLanes(alternate.lanes, lane);
	}
};

export function basicStateReducer<State>(
	state: State,
	action: Action<State>
): State {
	if (action instanceof Function) {
		// baseState 1 update (x) => 4x -> memoizedState 4
		return action(state);
	} else {
		// baseState 1 update 2 -> memoizedState 2
		return action;
	}
}

// 消费一个更新
// 要传入 初始状态
// 要传入 一个 pendingUpdate 要消费的 update
// 去看 扩展state计算机制 下面注释的 5大原则！！
export const processUpdateQueue = <State>(
	baseState: State, // 传进来的 hook.baseState
	pendingUpdate: Update<State> | null, //
	renderLane: Lane, // 此时更新对应的 优先级
	onSkipUpdate?: <State>(update: Update<State>) => void
): {
	memoizedState: State;
	baseState: State;
	baseQueue: Update<State> | null;
} => {
	const result: ReturnType<typeof processUpdateQueue<State>> = {
		memoizedState: baseState,
		baseState,
		baseQueue: null
	}; // 要返回的 结果里面包含 三个字段

	//  1 2  3 4 5 5.next 指向1   pendingUpdate 指向5  5是最后插入的
	// update 因为 是一个环状链表pendingUpdate指向最后插入的 update
	// pendingUpdate 是最后一个插入的update
	// pendingUpdate.next 是第一个插入的 update
	if (pendingUpdate !== null) {
		// 第一个update
		// 开始 first 和 pending都指向第一个 插入的 update
		const first = pendingUpdate.next;
		let pending = pendingUpdate.next as Update<any>;
		// pending.next 表示 第二个插入的 update

		let newBaseState = baseState; // 为开始的baseState 或者 第一次遇到没有匹配上的update 的时候上一次匹配到update的 计算结果 后面再遇到没有匹配上的就不会变了？？？
		// 如果一直都有匹配上 newBaseState 最后就等于 newState
		let newBaseQueueFirst: Update<State> | null = null; // baseQueue链表头
		let newBaseQueueLast: Update<State> | null = null; // baseQueue链表尾
		let newState = baseState; // newState 是每一次匹配上优先级 计算的保存的结果

		do {
			const updateLane = pending.lane;
			//NoLane  和任务lane 取交集 都等于 NoLane
			// 如果renderLane 和 lane 优先级相等 或者 updateLane 优先级 为NoLane isSubsetOfLanes 会返回true
			if (!isSubsetOfLanes(renderLane, updateLane)) {
				// 这个update 中的优先级 和传入的 renderLane 优先级 不等
				// 优先级不够 被跳过
				const clone = createUpdate(pending.action, pending.lane); // 复制一个 被跳过的这个 update

				onSkipUpdate?.(clone);

				// 判断 是不是第一个被跳过的
				if (newBaseQueueFirst === null) {
					// first u0 last = u0
					newBaseQueueFirst = clone; // 将当前被跳过的update 赋值给 baseQueue链表头
					newBaseQueueLast = clone; // 将当前被跳过的update 赋值给 baseQueue链表尾
					newBaseState = newState; // 然后 newBaseState 赋值为最后一个没被跳过的update计算后的结果
				} else {
					// 不是第一个被跳过的
					// first u0 -> u1 -> u2
					// last u2
					(newBaseQueueLast as Update<State>).next = clone; // 最后一个的next 指向新的这个被跳过的 update
					newBaseQueueLast = clone;
				}
			} else {
				// 当 当前触发更新的 renderLane 和 当前update的lane相等 或 update的lane为 noLane的时候 时候才去消费 update
				// 优先级足够

				if (newBaseQueueLast !== null) {
					// 这表示 之前已经有跳过的 update了
					// 后面所有的update 都要复制一份加入到baseQueue 中 且如果是 没有跳过的那 优先级降级为NoLane
					// 	后面 会result.baseQueue = newBaseQueueLast
					const clone = createUpdate(pending.action, NoLane);
					newBaseQueueLast.next = clone;
					newBaseQueueLast = clone; // 指向最后一个
				}

				const action = pending.action;
				if (pending.hasEagerState) {
					newState = pending.eagerState;
				} else {
					// 					// setState((preState)=> {a:1,...preStte})
					// 					// 这样 多次 dispatch((baseState)=>baseState+1) dispatch((baseState)=>baseState+1) dispatch((baseState)=>baseState+1)
					// 					// 就会 合并成一次 更新 最终 baseState 值是 三次连续dispatch 后到值的结构
					// 					// 只有相同优先级别的 lane的 update 才会被合并更新执行
					//         baseState 是上一次消费后的 baseState;
					newState = basicStateReducer(baseState, action);
				}
			}
			// 然后开始指向第二个update
			pending = pending.next as Update<any>;
		} while (pending !== first); //当 pending 不等于 第一个update的时候 说明还没循环完

		if (newBaseQueueLast === null) {
			// 本次计算没有update被跳过
			newBaseState = newState;
		} else {
			// 有被跳过的
			// 那就形成环状链表
			newBaseQueueLast.next = newBaseQueueFirst;
		}
		result.memoizedState = newState;
		result.baseState = newBaseState;
		result.baseQueue = newBaseQueueLast;
	}
	return result;
};

// 14课时候的版本
// export function processUpdateQueue<State>(
// 	baseState: State,
// 	pendingUpdate: Update<State> | null,
// 	renderLane: Lane
// ): { memoizedState: State } {
// 	const result: ReturnType<typeof processUpdateQueue<State>> = {
// 		memoizedState: baseState
// 	};
// 	//  1 2  3 4 5 5.next 执行1 pendingUpdate 指向5  5是最后插入的

// 	// update 因为 是一个环状链表pendingUpdate指向最后插入的 update
// 	// pendingUpdate 是最后一个插入的update
// 	// pendingUpdate.next 是第一个插入的 update

// 	if (pendingUpdate !== null) {
// 		// 开始 first 和 pending都指向第一个 插入的 update
// 		const first = pendingUpdate?.next;
// 		let pending = pendingUpdate.next as Update<any>;
// 		// pending.next 表示 第二个插入的 update
// 		do {
// 			// 先执行一次流程 因为 当只插入了 一个update 的时候first 和 pending.next 是相等的
// 			// 现场 第一个update 开始 执行
// 			if (renderLane === pending.lane) {
// 				// 当 当前触发更新的 lane 和 当前update的lane相等的时候 时候才去消费 update
// 				const action = pendingUpdate.action;
// 				if (action instanceof Function) {
// 					// setState((preState)=> {a:1,...preStte})
// 					// 这样 多次 dispatch((baseState)=>baseState+1) dispatch((baseState)=>baseState+1) dispatch((baseState)=>baseState+1)
// 					// 就会 合并成一次 更新 最终 baseState 值是 三次连续dispatch 后到值的结构
// 					// 只有相同优先级别的 lane的 update 才会被合并更新执行
//         baseState 是上一次消费后的 baseState;
// 					baseState = action(baseState);
// 				} else {
// 					// setState({a:1})
// 					baseState = action;
// 				}
// 			} else {
// 				console.log('不应该进入renderLane !== pending.lane', 'log');
// 			}
// 			pending = pending.next as Update<any>; // 然后开始执行 第二个update
// 		} while (first !== pending); //当 pending 不等于 第一个update的时候 说明还没循环完
// 	}
// 	result.memoizedState = baseState;
// 	return result;
// }

// 扩展state计算机制
// 扩展「根据lane对应update计算state」的机制，主要包括：

// 通过update计算state时可以跳过「优先级不够的update」

// 由于「高优先级任务打断低优先级任务」，同一个组件中「根据update计算state」的流程可能会多次执行，所以需要保存update

// 跳过update需要考虑的问题
// 如何比较「优先级是否足够」？

// lane数值大小的直接比较不够灵活。

// 如何同时兼顾「update的连续性」与「update的优先级」？

// // u0
// {
//   action: num => num + 1,
//   lane: DefaultLane
// }
// // u1
// {
//   action: 3,
//   lane: SyncLane
// }
// // u2
// {
//   action: num => num + 10,
//   lane: DefaultLane
// }

// // state = 0; updateLane = DefaultLane
// // 只考虑优先级情况下的结果：11
// // 只考虑连续性情况下的结果：13
// 每次以 baseQueue 中的 update 开始计算 baseQueue 是 baseQueue 和 peddingQueue 合并的结果
// 新增baseState、baseQueue字段：

// baseState是本次更新参与计算的初始state，memoizedState是上次更新计算的最终state

// 如果本次更新没有update被跳过，则下次更新开始时baseState === memoizedState

// 如果本次更新有update被跳过，则本次更新计算出的memoizedState为「考虑优先级」情况下计算的结果，
// baseState为「最后一个没被跳过的update计算后的结果」，下次更新开始时baseState !== memoizedState

// 本次更新「被跳过的update及其后面的所有update」都会被保存在baseQueue中参与下次state计算

// 本次更新「参与计算但保存在baseQueue中的update」，优先级会降低到NoLane

// <!-- 例子1 -->
// 这 update 链表是怎么产生的？ 可以这么理解
// 组件中dom绑定了三个事件  sate 初始值是 0
// const [state,setState] = useState(0)
// console.log(state,'log');
// 在滚动事件中
// srroll = (e)=>{// 滚动事件 对应的 优先级是 DefaultLane
//   setState((sate)=>state + 1)
// }
// 然后在 点击事件中
// onClick = (e)=>{// 点击事件 对应的 优先级是 SyncLane
//   setState(3);
// }

// 然后在 拖拽事件中

// 拖拽 = (e)=>{// 点击事件 对应的 优先级是 SyncLane
//    setState((sate)=>state + 10)
// }

// 然后用户的操作是这么操作的 触发滚动事件之后 DefaultLane 又点了下 触发了 点击事件 然后又去拖拽了下  触发了拖拽事件
// 然后就产生了下面三个对应优先级的 update的链表。
// 用户的三个操作会触发 2次更新 因为优先级同为DefaultLane会被合并成一次更新，然后SyncLane对应一次更新。
// 然后 不管怎么样 最后一次更新的结果 一定是 不管优先级 三个update 的状态 合并的结果 结果为13
// 第一次更新的状态 不用管

// // u0
// {
//   action: num => num + 1,
//   lane: DefaultLane
// }
// // u1
// {
//   action: 3,
//   lane: SyncLane
// }
// // u2
// {
//   action: num => num + 10,
//   lane: DefaultLane
// }

// /*
// * 第一次render
// * baseState = 0; memoizedState = 0;
// * baseQueue = null; updateLane = DefaultLane;
// * 第一次render 第一次计算
// * baseState = 1; memoizedState = 1;
// * baseQueue = null;
// * 第一次render 第二次计算
// * baseState = 1; memoizedState = 1;
// * baseQueue = u1;
// * 第一次render 第三次计算
// * baseState = 1; memoizedState = 11;
// * baseQueue = u1 -> u2(NoLane);
// */

// /*
// * 第二次render
// * baseState = 1; memoizedState = 11;
// * baseQueue = u1 -> u2(NoLane); updateLane = SyncLane
// * 第二次render 第一次计算
// * baseState = 3; memoizedState = 3;
// * 第二次render 第二次计算
// * baseState = 13; memoizedState = 13;
// */

// <!-- 假设这里不考虑 中断更新 -->
// 上面过程用文字解释是这样的
// 第一次更新：lane为DefaultLane
// 第一次计算：当前DefaultLane的优先级 lane 匹配到 update0 后 baseState变为1 memoizedState变为1
// * baseState = 1; memoizedState = 1;
// * baseQueue = null;

// 第二次计算：然后lane 和 u1 update的优先级 SyncLane 不匹配 就跳过 跳过后各状态的值
// * baseState = 1; memoizedState = 1;
// * baseQueue = u1;

// 第三次计算 ：然后 lane 和 u1 update的优先级 DefaultLane 匹配 计算后
// * baseState = 1; memoizedState = 11;
// * baseQueue = u1（SyncLane） -> u2(NoLane);  update2 的lane 变成了 NoLane

// 第二次更新：lane为SyncLane
// 此时的状态
// * baseState = 1; memoizedState = 11;
// * baseQueue = u1 -> u2(NoLane); updateLane = SyncLane
// 因为baseQueue有值 所以 去 和 baseQueue链表匹配
// 第一次计算：当前SyncLane的优先级 lane 匹配到 update1 后
// * baseState = 1; memoizedState = 1;
// * baseQueue = u1;
// 第二次计算：当前SyncLane的优先级 lane 和 u2的优先级 NoLane 匹配 因为是 SyncLane 和 noLane 所以 还是可以匹配上的  因为noLane 和 任何 lane求并集 还是等于 noLane 所以第二次结果为：
// * 第二次render 第二次计算
// * baseState = 13; memoizedState = 13;

// 所以最终的结果为13
